package com.jbjr.tianchi.service;

import com.jbjr.tianchi.Parments.*;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.List;

/**
 * @Author：zgh
 * @DATE: 2018/7/31 16:56
 * @version: 0.0.1
 * @Description:
 */
@Service
public class SearchSourceBuilderHandle {

    public SearchSourceBuilder handel(QueryEs param){

        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.from(param.getFrom());
        sourceBuilder.size(param.getSize());
        sourceBuilder.timeout(param.getTimeout());

        // 等同于bool，将两个查询合并
        BoolQueryBuilder boolBuilder = boolQueryBuilderHandel(param.getConditions());

        //组装区间查询条件
        boolBuilder =rangeQueryBuilderHandel(param.getIntervalParments(),boolBuilder);

        if(param.getAggregationBuildersParment() != null){
            TermsAggregationBuilder aggregation = AggregationBuilders.terms(param.getAggregationBuildersParment().getTermsKey()).field(param.getAggregationBuildersParment().getTerms());

            if(param.getAggregationBuildersParment().getMetrics() != null){
                switch (param.getAggregationBuildersParment().getMetrics()){
                    case AggregationBuildersParment.AVG:
                        aggregation.subAggregation(AggregationBuilders.avg(param.getAggregationBuildersParment().getMetricsKey()).field(param.getAggregationBuildersParment().getBuckets()));
                        break;
                    case AggregationBuildersParment.COUNT:
                        aggregation.subAggregation(AggregationBuilders.count(param.getAggregationBuildersParment().getMetricsKey()).field(param.getAggregationBuildersParment().getBuckets()));
                        break;
                    case AggregationBuildersParment.MAX:
                        aggregation.subAggregation(AggregationBuilders.max(param.getAggregationBuildersParment().getMetricsKey()).field(param.getAggregationBuildersParment().getBuckets()));
                        break;
                    case AggregationBuildersParment.MIN:
                        aggregation.subAggregation(AggregationBuilders.min(param.getAggregationBuildersParment().getMetricsKey()).field(param.getAggregationBuildersParment().getBuckets()));
                        break;
                    case AggregationBuildersParment.SUM:
                        aggregation.subAggregation(AggregationBuilders.sum(param.getAggregationBuildersParment().getMetricsKey()).field(param.getAggregationBuildersParment().getBuckets()));
                        break;
                }
            }

            sourceBuilder.aggregation(aggregation);
        }
        sourceBuilder.query(boolBuilder);
        if(param.getIncludeFields() != null)
                sourceBuilder.fetchSource(param.getIncludeFields(),param.getExcludeFields());

        // 排序
        if(!CollectionUtils.isEmpty(param.getSortParments())){
            param.getSortParments().forEach(sortParment -> {
                FieldSortBuilder fsb = SortBuilders.fieldSort(sortParment.getKey());
                switch (sortParment.getScore()){
                    case SortParment.ASC:
                        fsb.order(SortOrder.ASC);
                    case SortParment.DESC:
                        fsb.order(SortOrder.DESC);
                    default:
                        fsb.order(SortOrder.DESC);
                }
                sourceBuilder.sort(fsb);
            });
        }

        return sourceBuilder;

    }

    /**
     * 相似度匹配
     * @param conditions
     * @return
     */
    private BoolQueryBuilder boolQueryBuilderHandel(List<Condition> conditions){

        // 等同于bool，将两个查询合并
        BoolQueryBuilder boolBuilder = QueryBuilders.boolQuery();
        //增加字段k/v过滤
        if(!CollectionUtils.isEmpty(conditions)){
            conditions.forEach(condition -> {
                MatchQueryBuilder matchQueryBuilder =new MatchQueryBuilder(condition.getKey(),condition.getValue());//条件匹配查询关键字过滤
                if(condition.getFuzziness() != null)
                    matchQueryBuilder.fuzziness(condition.getFuzziness());
                if(condition.getPrefixLength() != null)
                    matchQueryBuilder.prefixLength(condition.getPrefixLength());
                if(condition.getMaxExpansions() != null)
                    matchQueryBuilder.maxExpansions(condition.getMaxExpansions());
                if(!StringUtils.isEmpty(condition.getOperator())){
                    switch (condition.getOperator()){
                        case Condition.OR:
                            matchQueryBuilder.operator(Operator.OR);
                        case Condition.AND:
                            matchQueryBuilder.operator(Operator.AND);
                        default:
                            matchQueryBuilder.operator(Operator.OR);
                    }
                }
                boolBuilder.must(matchQueryBuilder);
            });
        }

        return boolBuilder;
    }

    /**
     * 区间查询
     * @param intervalParments
     * @param boolBuilder
     * @return
     */
    private BoolQueryBuilder rangeQueryBuilderHandel(List<IntervalParment> intervalParments,BoolQueryBuilder boolBuilder){

        if(CollectionUtils.isEmpty(intervalParments)){
            return boolBuilder;
        }
        intervalParments.forEach(intervalParment -> {
            // 查询在时间区间范围内的结果
            RangeQueryBuilder rangbuilder = QueryBuilders.rangeQuery(intervalParment.getKey());
            if(!StringUtils.isEmpty(intervalParment.getStart()))
                rangbuilder.gte(intervalParment.getStart());
            if(!StringUtils.isEmpty(intervalParment.getEnd()))
                rangbuilder.lte(intervalParment.getEnd());
            boolBuilder.must(rangbuilder);
        });

        return boolBuilder;
    }






}
